#pragma once

#include "InetAddr.hpp"
#include "Socket.hpp"
#include "TcpServer.hpp"
#include "Util.hpp"
#include "Log.hpp"
#include <cstdint>
#include <functional>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <unordered_map>
#include <utility>

using namespace LogModule;
using namespace SocketModule;

const std::string gsp = " ";
const std::string glinespace = "\r\n";

const std::string webroot = "./wwwroot";
const std::string glinesep = ": "; // 默认分割符
const std::string homepage = "index.html"; // 默认首页
const std::string page_404 = "/404.html";
class HttpRequest { // 对http请求的处理
public:
    HttpRequest() : _is_interact(false){}
    ~HttpRequest() {}
    std::string Serialize() {
        return std::string();
    }
    bool Deserialisze(std::string str) {
        std::string reqline; // 对请求行进行提取
        bool res = Util::ReadOneLine(str, &reqline, glinespace);
        LOG(LogLevel::DEBUG) << reqline;

        // 对请求行进程反序列化
        // _uri: ./wwwroot/login?username=zhangsan&password=123456
        ParseReqLine(reqline);
        LOG(LogLevel::DEBUG) << "method: " << _method;
        LOG(LogLevel::DEBUG) << "uri: " << _uri;
        LOG(LogLevel::DEBUG) << "version: " << _version;
        if(_uri == "/") {
            _uri = webroot + _uri + homepage;
        }else {
            _uri = webroot + _uri;
        }
        const std::string temp = "?";
        auto pos = _uri.find(temp);
        if(pos == std::string::npos) {
            return true;
        }
        _args = _uri.substr(pos + temp.size());
        _uri = _uri.substr(0, pos);
        _is_interact = true;
        return true;
    }
    void ParseReqLine(std::string& reqline) { // 这里是用来提取我们的请求行相关信息的
        // 使用stringstream自动识别并提取
        std::stringstream ss(reqline);
        ss >> _method >> _uri >> _version; // 请求方法 请求的uri 请求的版本号
    }
    std::string uri() {
        return _uri;
    }
    bool isInteract() {
        return _is_interact;
    }
    std::string Args() {
        return _args;
    }
private:
    std::string _method;
    std::string _uri;
    std::string _version;
    std::unordered_map<std::string, std::string> _header;
    std::string _blankline;
    std::string _text;
    std::string _args;
    bool _is_interact;
};
class HttpResponse {
public:
    HttpResponse() : _blankline(glinespace), _version("HTTP/1.0") {
    }
    std::string Serialize() { // 序列化
        std::string status_line = _version + gsp + std::to_string(_code) + gsp + _desc + glinespace;
        std::string resp_header;
        for(auto& header : _headers) {
            std::string line = header.first + glinesep + header.second + glinespace;
            resp_header += line;
        }
        return status_line + resp_header + _blankline + _text;
    }
    void SetTargetFile(const std::string& tar) {
        _targetfile = tar;
    }
    void SetCode(int code) {
        _code = code;
        switch (_code) {
            case 200:
                _desc = "OK";
                break;
            case 404:
                _desc = "Not Found!";
                break;
            case 301:
                _desc = "Move Permanently";
                break;
            case 302:
                _desc = "See Other";
                break;
            default:
                break;
        }
    }
    void SetHeader(const std::string& key, const std::string& value) {
        auto it = _headers.find(key);
        if(it != _headers.end()) {
            return;
        }
        _headers.insert(make_pair(key, value));
    }
    std::string Uri2Suffix(const std::string& targetfile) // 后缀名处理函数
    {   
        auto pos = targetfile.rfind(".");
        if(pos == std::string::npos) {
            return "text.html";
        }
        std::string suffix = targetfile.substr(pos);
        if(suffix == ".html" || suffix == ".htm") {
            return "text/html";
        }else if(suffix == ".jpg") {
            return "image/jpg";
        }else if(suffix == ".png") {
            return "image/png";
        }else {
            return "";
        }
    }
    void SetText(const std::string& text) {
        _text = text;
    }
    bool MakeResponse() {
        if(_targetfile == "./wwwroot/favicon.ico") {
            LOG(LogLevel::DEBUG) << "用户请求：" << _targetfile << "忽略即可";
            return false;
        }
        if(_targetfile == "./wwwroot/redir_test") {
            SetCode(301);
            SetHeader("Location", "http://www.qq.com/");
            return true;
        }
        int filesize = 0;
        bool res = Util::ReadFileContent(_targetfile, &_text); // 读取正文部分
        if(!res) {
            _text = "";
            LOG(LogLevel::WARNING) << "用户想要获取；" << _targetfile << "但是没有找到";
            SetCode(404);
            _targetfile = webroot + page_404;
            filesize = Util::FileSize(_targetfile);
            Util::ReadFileContent(_targetfile, &_text);
            std::string suffix = Uri2Suffix(_targetfile);
            SetHeader("Content_Type", suffix);
            SetHeader("Content_Length", std::to_string(filesize));
        }else {
            LOG(LogLevel::DEBUG) << "读取文件：" << _targetfile;
            SetCode(200);
            filesize = Util::FileSize(_targetfile);
            std::string suffix = Uri2Suffix(_targetfile);
            SetHeader("Content_Type", suffix);
            SetHeader("Content_Length", std::to_string(filesize));
        }
        return true;
    }
    bool Deserialisze() {
        return true;
    }
public:
    std::string _version;
    int _code;
    std::string _desc;
    std::unordered_map<std::string, std::string> _headers;
    std::string _blankline;
    std::string _text;
    std::string _targetfile;
};
using func = std::function<void(HttpRequest& req, HttpResponse& resp)>;
class Http {
public:
    Http(uint16_t port) : ts(std::make_unique<TcpServer>(port)) {
    }
    void HandlerHttpRequset(std::shared_ptr<Socket>& sock, InetAddr& client) {
        std::string httpreqstr;
        int n = sock->Recv(&httpreqstr);
        if(n > 0) {
            std::cout << "********************************" << std::endl;
            std::cout << httpreqstr;
            std::cout << "********************************" << std::endl;
            HttpRequest req;
            req.Deserialisze(httpreqstr);
            HttpResponse resp;
            if(req.isInteract()) {
                if(_route.find(req.uri()) == _route.end()) {
                    // todo
                }else {
                    _route[req.uri()](req, resp);
                    std::string response_str = resp.Serialize();
                    sock->Send(response_str);
                }
            }else {
                resp.SetTargetFile(req.uri());
                if(resp.MakeResponse()) {
                    std::string response_str = resp.Serialize();
                    sock->Send(response_str);
                }
            }
            
        }
        // #define DEBUG
        // #ifdef DEBUG
        // 收到请求
        // std::string httpreqstr;
        // // 假设：概率大，读到了完整的请求
        // sock->Recv(&httpreqstr); // 浏览器给我发过来的是一个大的http字符串, 其实我们的recv也是有问题的。tcp是面向字节流的.
        // std::cout << httpreqstr;

        // // 直接构建http应答. 内存级别+固定
        // HttpResponse resp;
        // resp._version = "HTTP/1.1";
        // resp._code = 200; // success
        // resp._desc = "OK";

        // std::string filename = webroot + "/" + homepage; // "./wwwroot/index.html";
        // bool res = Util::ReadFileContent(filename, &(resp._text));
        // (void)res;
        // std::string response_str = resp.Serialize();
        // sock->Send(response_str);
        // #endif
    }
    void Start() {
        ts->Start([this](std::shared_ptr<Socket> &sock, InetAddr& client) {
            this->HandlerHttpRequset(sock, client);
        });
    }
    void RegisterService(const std::string& name, func cb) {
        std::string key = webroot + name;
        auto it = _route.find(key);
        if(it == _route.end()) {
            _route.insert(make_pair(key, cb));
        }
    }
    ~Http() {
        
    }
private:
    std::unique_ptr<TcpServer> ts;
    std::unordered_map<std::string, func> _route;
};